/**
 *	The NeuroCoSA Toolkit
 *	Copyright (C) 2003-6 Stuart Meikle.
 *
 *	This is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation; either
 *	version 2.1 of the License, or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	Lesser General Public License for more details.
 *
 * @author	Stuart Meikle
 * @version	2006-halloween(mk2)
 * @license	LGPL
 */
package org.stumeikle.NeuroCoSA;

/* Comments:
 stumeikle 20051010

 all new simple lobe class
*/

import java.util.*;
import java.lang.*;
import org.stumeikle.NeuroCoSA.NIS.*;

/**
 * Simple Lobe. A lobe baseclass. Here we introduce expectation related software and
 * so need a new base class. Assumes consequently that all neurons are derived from simple
 * neuron. Also we modify the update neurons routines from bimodelayer to enable
 * drive controller information to be stored. 
 *
 * Stumeikle 20051010, 20070103
 *
 */
public	class	SimpleLayer extends BiModeLayer
{
    InfoWithSingleStore 	iDriveController;//controlling synapse
    Synapse			iTmpDriveController;

    private void	construct()
    {
	iDriveController = new InfoWithSingleStore( "DriveController", this );
	getInfoService().addPublication( iDriveController );
    }
    
    public SimpleLayer(Cortex c)
    { super(c);
      construct();
    }

    protected void			simpleResetVars()
    {
	iTmpDriveController = null;
    }

    protected void 			simpleUpdateVars(SimpleNeuron sn)
    {
	//update the vars depending on the firing strength of n and its mode
	boolean		state_active = false;

	//20060521 We must update even the inhibited neurons else we'll miss the max learn signal
	//if there is a drive inhibition active. this means we can't learn when success occurs.
	if ( sn.getState() == Neuron.state_excited || 
	     sn.getState() == Neuron.state_inhibited)
	    state_active = true;

System.out.println("Setting Drive Controller (check1). drive str= " + sn.getDriveSigStr() + " tmp win=" + getTmpWinningDriveStrength());
	if ( sn.drivesMustCompete() &&  (state_active && sn.getDriveSigStr() >= getTmpWinningDriveStrength() ) )
	{
System.out.println("Setting Drive Controller (check2). setting controller");
	    try{
	    iTmpDriveController  = sn.getDriveController();
	    }catch(Exception e)
	    { System.out.println("Drive Controller Irrelevant Exception");
		System.exit(-1);
		//whata load of old cock
	    }
	}
    }

    protected 		void		simpleTransferVarsToLIS()
    {
System.out.println("Setting Drive Controller = " + iTmpDriveController);
	iDriveController.setValue( iTmpDriveController );
    }

    /*----------------------------------------------------------------------------------------
     * Service Methods 
     */
    public	final 	void		notifyDriveAcceptances( SimpleNeuron winner )
    {
    	/** A service provided by simple lobe , a method by which the output lobes / brain 
     	 *  can notify neurons of their accepted drive status or their failure
     	 */
    	/** update all the neurons. For neuron =winner call neuron.notifyDriveAccepted()
	 *  for the others , driven or otherwise, call neuron.notifyDriveNotAccepted()
	 */
	 ListIterator		i = getNeurons().listIterator();
// 	 SimpleInfoService	sis = (SimpleInfoService)getLobeInfoService(); do we need this?
	 
	 for(;i.hasNext();)
	 {
	     SimpleNeuron	sn = (SimpleNeuron)i.next();
	     if (sn==winner)
	       	sn.notifyDriveAccepted();
	     else
	     	sn.notifyDriveNotAccepted();
		
	     //propagate the info to the LIS
	     //don't really need to do this for every neuorn but ... more complete
	     //removed 20060606 stumeikl
	     //sis.updateDriveStatus( sn );
	 }
    }

    //new routines 20070103 stumeikle
    public 	void			updateNeurons()/// I expect this to be overloaded in bimodelayer later
    {
	//update as in the base class but extend to update simple-layer variables too
	super.resetVars();
	simpleResetVars();

	ListIterator		i = getNeurons().listIterator(0);
	for(;i.hasNext();)
	{
	    BiModeNeuron	bmn = (BiModeNeuron)i.next();
	    SimpleNeuron	sn  = (SimpleNeuron)bmn;
	    
	    bmn.update();
	
	    super.updateVars(bmn);
	    simpleUpdateVars((SimpleNeuron) bmn);
	}

	super.transferVarsToLIS();
	simpleTransferVarsToLIS();
    }

    public	void			updateNeurons(Vesicle lv)
    {
    	super.resetVars();
	simpleResetVars();

	//changed. stumeikle20070310
	ListIterator		i = getNeurons().listIterator();
	for(;i.hasNext();)
	{
	    BiModeNeuron	bmn = (BiModeNeuron)i.next();
	    SimpleNeuron	sn  = (SimpleNeuron)bmn;
	    
	    bmn.update(lv);
	
	    super.updateVars(bmn);
	    simpleUpdateVars( sn );
	}
	
	super.transferVarsToLIS();
	simpleTransferVarsToLIS();
    }

    //most likely we can remove this in future and use startUpdate method in the
    //neurons to achieve the same effect
    protected void			notifyAutoClusterNeurons()
    {
	//a helper routine
	//go through the list of neurons and trigger each to upload/consider
	//autocluster input
	LinkedList< AutoClusterNeuronIF > 	l;

	try
	{ 
	    l = (LinkedList<AutoClusterNeuronIF>) getNeurons() ;
	    ListIterator			i = l.listIterator();

	    for(;i.hasNext();)
	    {
	    	AutoClusterNeuronIF		a = (AutoClusterNeuronIF) i.next();

	    	a.storeACMInput();
	    }
        }catch(Exception e){}
    }


//ADD
//  public void updateWithLateralInhibition from baseclass. follow same methodology as above. 


/* ADD if wanted
    public	SimpleLobe	getOutputLobeByName( String a)
    {
	//scan the output lobes and return the first that matches the given named lobe
	LinkedList	l = getOutputs();
	ListIterator	i = l.listIterator(0);

System.out.println("DEBUG:getOutputLobeByName:start. A = " + a);
	for(;i.hasNext();)
	{
	    SimpleLobe 	sl = (SimpleLobe) i.next();
	
System.out.println("DEBUG:getOutputLobeByName:found lobe with name=" + sl.getUniqueName() + " and comparing to " + a );

	    if (sl.getUniqueName().compareTo(a) == 0 )
		return sl;
	}

	return null;
    }
*/
}
